package com.zg.nacos.web;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.zg.common.core.R;
import com.zg.nacos.domain.entity.MicroUser;
import com.zg.nacos.domain.req.*;
import com.zg.nacos.domain.vo.GrafanaLoginVo;
import com.zg.nacos.domain.vo.LoginVo;
import com.zg.nacos.domain.vo.MicroUserVo;
import com.zg.nacos.service.MicroUserService;
import com.zg.nacos.util.NacosUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriBuilder;
import reactor.core.publisher.Mono;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>Description: </p>
 *
 * @author zhanfeng.liang
 * @since 2025/6/20 16:11
 */

@RestController

@Api(tags = "nacos服务")
@Slf4j
public class NacosUserController {

    @Value("${spring.cloud.nacos.username}")
    private String userName;
    @Value("${spring.cloud.nacos.password}")
    private String password;

    @Value("${username.forbid}")
    private List<String> forbid;

    @Autowired
    private MicroUserService microUserService;
    @Autowired
    private WebClient webClient;

    @Autowired
    private WebClient grafanaClient;

    @ApiOperation(value = "用户列表")
    @PostMapping("/nacos/user/page")
    public R pageUser(@Valid @RequestBody UserPageReq userPageReq) {
        return webClient.get()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("nacos/v1/auth/users");
                    // 仅当参数非空时才添加 queryParam
                    if (!StrUtil.isEmpty(userPageReq.getUsername())) {
                        builder.queryParam("username", "*" + userPageReq.getUsername() + "*");
                    }
                    builder.queryParam("pageSize", userPageReq.getPageSize());
                    builder.queryParam("pageNo", userPageReq.getPageNo());
                    builder.queryParam("search", "accurate");
                    return builder.build();
                })
//                .header("username", userName)
//                .header("password", password)
                .retrieve()
                .bodyToMono(Map.class)
                .map(response -> NacosUtils.genPage(response, userPageReq.getPageNo(), userPageReq.getPageSize()))
                .block(Duration.ofSeconds(5));
    }

    @ApiOperation(value = "用户登录")
    @PostMapping("/un/nacos/user/login")
    public R login(@Valid @RequestBody UserEditReq editReq,HttpServletResponse servletResponse) {
        if(StrUtil.equals("admin",editReq.getUsername())){
            editReq.setUsername("nacos");
        }
        MicroUser microUser = microUserService.getByUsername(editReq.getUsername());
        if (microUser == null) {
            return R.error();
        }

        LoginVo loginVo = loginNacos(editReq.getUsername(), microUser.getMicroPwd());

        return R.success(loginVo);

    }

    private @Nullable LoginVo loginNacos(String username, String password) {
        LoginVo loginVo = webClient.post()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/login");
                    builder.queryParam("username", username);
                    builder.queryParam("password", password);
                    // 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .retrieve()
                .bodyToMono(LoginVo.class)
                .block(Duration.ofSeconds(5));
        MicroUser microUserVo =microUserService.getByUsername(username);
        if(microUserVo!=null){
            loginVo.setNamespaceId(microUserVo.getNacosResource());
        }
        return loginVo;
    }
    @PostMapping("/un/nacos/user/loginGrafana")
    public R loginGrafana(@Valid @RequestBody UserEditReq editReq,HttpServletResponse servletResponse) {
        try {
            loginGrafana(editReq.getUsername(), "qaz@Pwd123456", servletResponse).block(Duration.ofSeconds(5));

        }catch (Exception e){
            e.printStackTrace();
        }
        return R.success();
    }
    private @Nullable Mono<Void> loginGrafana(String username, String password, HttpServletResponse servletResponse) {
        Map<String, String> jsonData = new HashMap<>();
        jsonData.put("user", username);
        jsonData.put("password", password);
        return  grafanaClient.post()
                .uri("/login")
                .bodyValue(jsonData)
                .exchangeToMono(response -> {
                    if (response.statusCode().is2xxSuccessful()) {
                        // 提取响应中的 Cookie
                        List<ResponseCookie> cookies = response.cookies().values().stream()
                                .flatMap(List::stream)
                                .collect(Collectors.toList());

                        // 将 Cookie 设置到 HTTP 响应中
                        cookies.forEach(cookie -> {
                            javax.servlet.http.Cookie servletCookie = new javax.servlet.http.Cookie(
                                    cookie.getName(),
                                    cookie.getValue()
                            );
                            servletCookie.setPath(cookie.getPath());
                            if (cookie.getDomain() != null) {
                                servletCookie.setDomain(cookie.getDomain());
                            }
                            servletCookie.setMaxAge((int) cookie.getMaxAge().getSeconds());
                            servletCookie.setSecure(cookie.isSecure());
                            servletCookie.setHttpOnly(cookie.isHttpOnly());
                            servletResponse.addCookie(servletCookie);
                        });
                        return Mono.empty(); // 返回空响应表示登录成功
                    } else {
                        return Mono.error(new RuntimeException("Login failed: " + response.statusCode()));
                    }
                });
    }

    // 从响应头中提取session cookie
    private Mono<String> extractSessionCookie(ClientResponse response) {
        List<String> cookies = response.headers().header(HttpHeaders.SET_COOKIE);
        Optional<String> sessionCookie = cookies.stream()
                .filter(cookie -> cookie.startsWith("grafana_session="))
                .findFirst();

        return sessionCookie.map(Mono::just)
                .orElseGet(() -> Mono.error(new RuntimeException("未找到grafana_session cookie")));
    }

    // 使用session cookie获取仪表盘列表
    public Mono<String> getDashboards(String sessionCookie) {
        return webClient.get()
                .uri("/api/search")
                .header(HttpHeaders.COOKIE, sessionCookie)
                .retrieve()
                .bodyToMono(String.class);
    }

    @ApiOperation(value = "用户删除")
    @PostMapping("/nacos/user/remove")
    public R removeUser(@Valid @RequestBody UserRemoveReq removeReq) {

        Map map = webClient.delete()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/users");
                    builder.queryParam("username", removeReq.getUsername());
//                    builder.queryParam("accessToken",removeReq.getNacosToken());
                    // 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));
        return NacosUtils.handleResponse(map);

    }


    @ApiOperation(value = "用户角色权限新增")
    @PostMapping("/nacos/user/addAll")
    public R addUserAll(@Valid @RequestBody UserEditReq editReq) {
        if(forbid.contains(editReq.getUsername())){
            return R.error("用户名称包含禁止词条");
        }
        editReq.setRole(editReq.getUsername());
        LoginVo loginVo = this.loginNacos(userName, password);
        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();

        // 使用add方法添加表单字段（更适合multipart/form-data）
        formData.add("username", editReq.getUsername());
        formData.add("password", editReq.getNacosPwd());

        webClient.post()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/users");
                    builder.queryParam("accessToken", loginVo.getAccessToken());
                    // 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(formData))
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));

        formData = new LinkedMultiValueMap<>();

        // 使用add方法添加表单字段（更适合multipart/form-data）
        formData.add("username", editReq.getUsername());
        formData.add("role", editReq.getUsername());

        webClient.post()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/roles");
                    builder.queryParam("accessToken", loginVo.getAccessToken());// 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(formData))
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));
        formData = new LinkedMultiValueMap<>();

        // 使用add方法添加表单字段（更适合multipart/form-data）
        formData.add("role", editReq.getUsername());
        formData.add("resource", editReq.getResource()+":*:*");
        formData.add("action", "rw");

        webClient.post()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/permissions");
                    builder.queryParam("accessToken", loginVo.getAccessToken());
                    return builder.build();
                })
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(formData))
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));

        MicroUser microUser = new MicroUser();
        microUser.setUsername(editReq.getUsername());
        microUser.setMicroPwd(editReq.getNacosPwd());
        microUser.setNacosRole(editReq.getRole());
        microUser.setNacosResource(editReq.getResource());
        microUserService.add(microUser);

        return R.success();
    }

    @ApiOperation(value = "用户角色权限删除")
    @PostMapping("/nacos/user/removeAll")
    public R removeAll(@Valid @RequestBody UserRemoveReq editReq) {
        LoginVo loginVo = this.loginNacos(userName, password);
        MicroUser microUser = microUserService.getByUsername(editReq.getUsername());
        webClient.delete()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/users");
                    builder.queryParam("username", editReq.getUsername());
                    builder.queryParam("accessToken", loginVo.getAccessToken());
                    // 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));

        webClient.delete()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/roles");
                    builder.queryParam("username", microUser.getUsername());
                    builder.queryParam("role", microUser.getNacosRole());
                    builder.queryParam("accessToken", loginVo.getAccessToken());
                    // 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));

        // 使用add方法添加表单字段（更适合multipart/form-data）
        webClient.delete()
                .uri(uriBuilder -> {
                    UriBuilder builder = uriBuilder.path("/nacos/v1/auth/permissions");
                    builder.queryParam("action", "rw");
                    builder.queryParam("role", microUser.getNacosRole());
                    builder.queryParam("resource", microUser.getNacosResource());
                    builder.queryParam("accessToken", loginVo.getAccessToken());
                    // 仅当参数非空时才添加 queryParam
                    return builder.build();
                })
                .retrieve()
                .bodyToMono(Map.class)
                .block(Duration.ofSeconds(5));

        microUserService.removeByUsernames(Lists.newArrayList(microUser.getUsername()));

        return R.success();
    }
}